Part 1: Introduction to estimating biological diversity

What is the goal?

Often, we are interested in describing the richness and structure or diversity of an assemblage. But more importantly, we are often more interested in comparing richness and diversity across space and/or time, by merging data from multiple sites or from different sampling units within a site.

By richness, we mean the number of unique species or taxonomic/phylogenetic/functional units in the assemblage. By diversity, we usually mean some aspect of the structure of the assemblage - a combination of both the number of unique elements as well as the relative abundance of the different elements.

Overall, biological diversity metrics can be characterized as:

  1. Richness metrics : number of species
  2. Evenness metrics : capture the distribution of abundance among species
  3. Diversity metrics : combines both richness and evenness
  4. Dominance metrics : somewhat the inverse of evenness, focused on the most common species (not covered)

Today, we will be exploring different aspects of estimating richness and diversity. A good resource for this topic, and one on which I have relied heavily in this lecture (in addition to package vignettes), is the book “Biological Diversity” by Magurran and McGill https://global.oup.com/academic/product/biological-diversity-9780199580675?cc=us&lang=en&. This book may be available through your institutional library.

Part 2: Getting started with R

We will need to load all relevant package

rr # uncomment the following line if you haven’t installed these packages yet # install.packages(c(‘vegan’, ‘neotoma’, ‘dplyr’, ‘sads’, ‘iNEXT’))

library(‘vegan’) library(‘neotoma’) library(‘dplyr’) library(‘sads’) library(‘iNEXT’)

Part 3: Diversity analyses for a single site through time

Download data for a single site

Let’s start with a simple search for a single site in the Neotoma Paleoecology Database https://www.neotomadb.org/. We’ll download mammal data from one site (late Quaternary cave deposit) in northern California, Samwell Cave Popcorn Dome, along with the corresponding ages of the sampled units.

rr samwell_site <- get_site(sitename=Cave) #there’s one site in the database that matches this samwell_datasets <- get_dataset(samwell_site[[1]]) # this search lists all datasets associated with Samwell Cave. There are 7 different datasets for the site: 4 containing vertebrate faunal information and 3 containing geochronologic information. browse(samwell_datasets) # Note that this opens a new window in your browser

Download info for just the last dataset, 14262.

scpd_dataset <- get_dataset(samwell_site[[1]])$‘14262’ scpd_download <- get_download(scpd_dataset)

Extract the count data and the sample ages

scpdFauna <- counts(scpd_download)[[1]] scpdAges <- ages(scpd_download)[[1]]

save as R object for later upload in case no internet or API not working

save(scpdFauna, scpdAges, file=/scpdObjects.RData)

Note: Dataset 14261 contains the underlying radiocarbon dates for the site, in case you want to examine those. You’ll need to uncomment the next two lines

scpd_geochron <- get_geochron(14261)

scpd_geochron[[1]]$geochron

Clean up the assemblage/site data

OK, now that we have the basic dataset downloaded, we will need to clean up the data.

Question:

What kinds of data cleaning might we want to do here?

It’s often helpful to examine the structure of the data to answer this question.

rr # examine the final downloaded file str(scpdFauna) # another possible way to examine the data: glimpse(scpdFauna)

'data.frame':   14 obs. of  22 variables:
 $ Carnivora                       : num  1 0 0 0 0 0 0 0 0 0 ...
 $ cf. Scapanus latimanus          : num  1 1 2 3 2 1 1 0 3 2 ...
 $ Chiroptera                      : num  3 8 5 13 9 5 14 3 11 7 ...
 $ Leporidae                       : num  3 2 0 0 1 0 2 2 1 0 ...
 $ Microtus sp.                    : num  38 30 15 51 40 31 32 13 15 19 ...
 $ Neotoma sp.                     : num  32 44 28 35 28 20 39 14 28 24 ...
 $ Peromyscus sp.                  : num  151 171 136 220 203 112 184 77 132 114 ...
 $ Sorex sp.                       : num  4 2 2 3 6 0 2 0 4 0 ...
 $ Spermophilus beecheyi           : num  1 1 2 4 4 1 5 3 4 2 ...
 $ Tamias sp.                      : num  1 0 0 1 1 0 0 1 1 3 ...
 $ Tamiasciurus douglasii          : num  1 1 1 2 1 2 1 0 3 2 ...
 $ Thomomys bottae                 : num  5 9 2 6 6 1 1 3 1 1 ...
 $ Thomomys sp.                    : num  14 18 23 42 25 19 24 18 21 30 ...
 $ cf. Arborimus albipes           : num  0 1 0 0 0 0 1 1 1 1 ...
 $ Reithrodontomys cf. R. megalotis: num  0 1 1 1 0 0 0 0 1 0 ...
 $ Sciurus griseus                 : num  0 1 1 3 1 1 2 0 3 0 ...
 $ Spermophilus lateralis          : num  0 2 0 1 0 1 1 0 2 1 ...
 $ Glaucomys cf. G. sabrinus       : num  0 0 0 2 1 0 1 0 0 0 ...
 $ Thomomys cf. T. mazama          : num  0 0 0 0 2 0 3 0 1 5 ...
 $ Artiodactyla                    : num  0 0 0 0 0 0 2 0 0 0 ...
 $ Myodes cf. M. californicus      : num  0 0 0 0 0 0 2 0 0 0 ...
 $ Aplodontia rufa                 : num  0 0 0 0 0 0 0 0 0 0 ...

rr head(scpdFauna)

Start cleaning up the data files.

rr # What are the rownames showing?
# Let’s replace the sample ID in the fauna object (rownames) with the ages # but only do this if the sample IDs match across objects ages <- scpdAges\(age if (all(rownames(scpdFauna) == scpdAges\)sample.id)){ rownames(scpdFauna) <- ages } # set the names of the small mammal genera of interest # note: this is a clunky workaround - ideally we’d be able to harmonize taxonomy using the database/API tools, but they aren’t as good in Neotoma as in PBDB because of the way taxonomy is handled sm_genus <- c(, , , , , , , , , , , , , , ) # create a new dataframe with the merged data scpdSM <- matrix(nrow=nrow(scpdFauna), ncol=length(sm_genus)) for (i in 1:length(sm_genus)){ cols <- grep(sm_genus[i], colnames(scpdFauna)) if (length(cols)==1){ scpdSM[,i] <- scpdFauna[,cols] } if (length(cols) > 1){ scpdSM[,i] <- rowSums(scpdFauna[,cols]) }

} # clean up dataframe colnames(scpdSM) <- sm_genus rownames(scpdSM) <- rownames(scpdFauna) save(scpdSM, file=/scpdFauna_cleaned.RData)

Richness analyses

Rarefaction-based estimates

First, let’s calculate raw richness, for each sample through time

rr # we can practice building our own functions to count up the species countFcn <- function(df){ count <- length(which(df>0)) return(count) } raw.S <- apply(scpdSM, 1, countFcn) # or you can do the same calculation using a built-in function (specnumber) in vegan specnumber(scpdSM)

 752.31 2758.47  4639.2  5893.1  7021.6  7899.3  8902.3 10156.2   11410 12663.9 13917.7 15171.6 
      9      12      11      12      11       9      13       7      12       9      13      11 
16425.4 17679.3 
     12      12 

However, we know these are fossil data and (even if they weren’t!) sampling effort may have varied through time and across samples. ie, the total sample size (N) of each sample (stratum) varies substantially, as can be seen by examining the range of total N.

rr range(rowSums(scpdSM))

[1] 130 376

rr minN <- min(rowSums(scpdSM))

So one approach is rarefy each assemblage down to the minimum N when calculating richness. This effectively answers: What is the expected richness of an assemblage if we sampled the same number of individuals as were observed in some other assemblage? You did this manually in Seth’s section, and then he also introduced you to the function rarefy in the vegan package. rarefy “gives the expected species richness in random subsamples of size sample from the community” (from help doc) and performs this for all samples/assemblages in the community matrix.

rr richness <- rarefy(scpdSM, sample=minN, se=T) # because I specified se=T, this function outputs both S and se S <- richness[1,] S.se <- richness[2,] # plot the result through time using base R plotting function plot(S ~ ages, type=, xlim=c(21000, 0), ylim=c(0, floor(max(S+S.se))+1), xlab=(cal BP), ylab=expression(‘Richness’ %+-% ‘se’)) #arrows(ages, S+S.se, ages, S-S.se, code=3, length=0.1, angle=90) suppressWarnings(arrows(ages, S+S.se, ages, S-S.se, code=3, length=0.1, angle=90))

rr # Note: use suppressWarnings with caution. I added the suppressWarnings tag so that the only thing output is the plot. But I only did this after I confirmed that the warning message was ok. Switch the arrows lines that are commented/uncommented and re-run the plot with that line of code for arrows to view the warning and decide for yourself whether it should be suppressed or not.

Let’s compare rarefied to raw richness, for each sample through time

rr plot(raw.S ~ ages, type=, xlim=c(21000, 0), ylim=c(0, max(raw.S)+1), lty=2, col=, xlab=(cal BP), ylab=‘Richness’) lines(S ~ ages, type=) r arrows(ages, S+S.se, ages, S-S.se, code=3, length=0.1, angle=90)

zero-length arrow is of indeterminate angle and so skipped

We can also compare the sampling curves using function rarecurve. This grabs random samples of different numbers of individuals in a step-wise function, then calculates richness for each sample.

rr # set colors, from cool for the older (LGM) times and red for the warmer (Holocene) times ageColors <- rainbow(length(ages), start=0, end=4/6) rarecurve(scpdSM, col=ageColors)

Extrapolation-based estimates of richness

Rarefaction calculates the expected richness if the same number of individuals were sampled across different samples. However, there are other ways to estimate richness and compare among samples. Among the more common alternatives to rarefaction are the Chao and ACE (Abundance-based Coverage Estimator) estimators of richness. Let’s first calculate them, and then discuss.

rr ?estimateR # read more about this function, and how ACE and Chao1 are calculated alt_richness <- estimateR(scpdSM) # Bind all richness estimates together and compare: richness_all <- rbind(alt_richness, richness) # plot them against one another y.max <- floor(max(richness_all))+1 # set y max for plotting mainEstimates <- c(‘S.obs’, ‘S.chao1’, ‘S.ACE’, ‘S’) plotRows <- match(mainEstimates, rownames(richness_all)) plotCols <- c(, , , )

i=1 plot(richness_all[plotRows[i],] ~ ages, type=, ylim=c(0, y.max), xlim=c(21000, 0), xlab=(cal BP), ylab=, col=plotCols[i]) for (i in 2:length(plotRows)){ lines(richness_all[plotRows[i],] ~ ages, col=plotCols[i]) } r legend(, legend=mainEstimates, lty=1, col=plotCols, bty=, cex=0.75)

Discussion

You can see that these two approaches (rarefaction vs extrapolation) produce fundamentally different estimates of the trend of species richness through time. Individual-based rarefaction (S) shows a trend towards lower richness from the Pleistocene to the Holocene, whereas ACE and Chao1 estimates show a trend towards higher richness from the Pleistocene to the Holocene.

So what’s the difference? Individual-based rarefaction (S) estimates expected richness given a subsample of n individuals from the assemblage. It’s a simple form of standardization so that different samples are comparable. In this case, n is sampled at the minimum N observed among the samples (N=130). And since n is generally lower than the total N sampled, it’s really an underestimate of on-the-ground richness.

On the other hand, Chao1 and ACE estimate the asymptotic richness estimates. ie, they both try to extrapolate beyond the sampled individuals to figure out the expected richness if the assemblage was sampled completely. They focus in particular on information in the detected rare species (singletons, etc) to estimate undetected species.

Chao1 and ACE have been shown to perform better than other estimators in various studies. They are also similar to (or fundamentally the same as) SQS. A recent study (Close et al. 2018) examined differences among richness estimators and found “sampling in the tetrapod fossil record is generally not yet good enough to use extrapolators unless they are applied within a rarefy‐and‐extrapolate protocol of the kind used in our simulation experiments” and “In particular, rarefying extrapolators to equal coverage is the best way to remove confounding effects of among‐sample variation in evenness, a problem that affects all richness estimators when sampling is comparatively limited”. The package iNEXT implements this rarefying extrapolators for Chao1, so let’s do a quick tour through that package.

rr # this chunk uses the iNext package vignette(, package=) iNextRichness <- iNEXT(t(scpdSM)) # Note 1: we had to transpose the community matrix # Note 2: this calculates not just richness, but also Shannon and Simpson diversities. # You can also rarefy within iNEXT using estimateD D_minN <- estimateD(t(scpdSM), datatype=, base=, level=NULL) D_minN r # Note 1: SC = sample coverage, qD is the estimate with lower and upper confidence levels # Note 2: Richness estimates here are the same as using rarefy in vegan. e.g., compare the following: D_minN[which(D_minN$order == 0),]$qD

 [1]  7.288  8.308  8.971  9.257  8.342  8.059  9.174  7.000 10.889  8.306 11.281 10.424 10.190
[14] 10.502

rr richness[1,]

   752.31   2758.47    4639.2    5893.1    7021.6    7899.3    8902.3   10156.2     11410 
 7.288080  8.308185  8.971041  9.257188  8.341658  8.058694  9.173950  7.000000 10.889424 
  12663.9   13917.7   15171.6   16425.4   17679.3 
 8.305880 11.281020 10.424141 10.190165 10.502225 

Plot the Chao estimators

rr ggiNEXT(iNextRichness) ggiNEXT(iNextRichness, type=1, facet.var=) ggiNEXT(iNextRichness, type=2)

Other diversity measures

OK, up to now we’ve just been counting the number of species in different ways. The other aspect of assemblages is their abundance structure - how abundance varies among the different species in the deposit.

Diversity

There are several common diversity measures, which combine both richness and evenness. I think it’s helpful to view the calculations for these by looking at one of the vegan vignettes

rr vignette(-vegan) H <- diversity(scpdSM, index=) Simp <- diversity(scpdSM, index=)

Practice calculating Shannon on your own

rr # Shannon pi.SCPD <- scpdSM/rowSums(scpdSM) pi.SCPDxlogpi <- pi.SCPD * log(pi.SCPD) sums_shan <- rowSums(pi.SCPDxlogpi, na.rm=T) H_calc <- -sums_shan all(H==H_calc)

[1] TRUE

rr # Simpson pi.SCPD2 <- pi.SCPD^2 sums_simp <- rowSums(pi.SCPD2, na.rm=T) Simp_calc <- 1-sums_simp all(Simp==Simp_calc)

[1] TRUE

Evenness

You were introduced to evenness is Seth’s lecture. There aren’t good built-in functions for calculating evenness (that I know of), but Pielou’s (or Shannon) evenness can be derived from Shannon diversity (H). (H/ln(S)). The idea underlying both of these measures is that if diversity incorporates both richness and evenness, then factoring out richness from the diversity measures should leave us with evenness.

rr Shan_even <- H/log(specnumber(scpdSM)) Simp_even <- Simp/log(specnumber(scpdSM))

Let’s plot these through time

rr plotCols <- c(, , , ) plot(H~ages, type=, ylim=c(0, 2), xlim=c(21000, 0), xlab=(cal BP), ylab=, col=plotCols[1]) lines(Simp~ages, col=plotCols[2]) r lines(Shan_even~ages, col=plotCols[3], lty=2) lines(Simp_even~ages, col=plotCols[4], lty=2) r legend(, legend=c(, , _Shannon, _Simpson), lty=c(1,1,2,2), col=plotCols, bty=, cex=0.75)

Note: you could also calculate Shannon and Simpson through iNext (as above), and probably using several other packages.

Part 4: Extending these analyses to multiple sites

Let’s ask: How do richness, evenness, and diversity vary across latitude and longitude? We will use a dataset of Quaternary fossil pollen data from eastern North America for 6000 years before present.

Note, this is not count data - the data are provided as the relative abundance of each taxon at the site - so the rarefaction and extrapolation estimators don’t work. They only accept count data / integers.

Data loading and prep

rr # load the data and examine the structure pollen.6000 <- read.csv(file=/pollen/6000.interp.data_clean_sites.csv) str(pollen.6000)

'data.frame':   369 obs. of  108 variables:
 $ sites                  : Factor w/ 369 levels \3PINES\,\ALEXISLK\,..: 1 2 3 4 5 6 7 8 9 10 ...
 $ Sambucus               : num  0 0 0 0 0 ...
 $ Viburnum               : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Liquidambar            : num  0 0 0 0 0.00645 ...
 $ Salsola                : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Allium                 : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Ilex                   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Nemopanthus            : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Ambrosia.type          : num  0 0 0 0 0.00216 ...
 $ Artemisia              : num  0.04612 0 0 0.00282 0 ...
 $ Bidens                 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Iva                    : num  0 0 0 0 0 ...
 $ Xanthium               : num  0 0 0 0 0.000714 ...
 $ Alnus                  : num  0.0777 0 0.0384 0.4222 0.5674 ...
 $ Corylus                : num  0 0.001024 0 0 0.000714 ...
 $ Ostrya.Carpinus        : num  0.08625 0 0 0 0.00574 ...
 $ Betula                 : num  0.1981 0.1422 0.2306 0.2425 0.0187 ...
 $ Bursera                : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Opuntia                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Celtis                 : num  0 0 0 0 0 ...
 $ Trema                  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Diervilla              : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Lonicera               : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Linnaea.borealis       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Symphoricarpos         : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Stellaria              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Clethra                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Cornus                 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Nyssa                  : num  0 0 0 0 0.00286 ...
 $ Juniperus.Thuja        : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Taxodium               : num  0 0 0 0 0 ...
 $ Cyrilla.racemiflora    : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Diapensia              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Shepherdia             : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Ephedra                : num  0 0 0 0 0 ...
 $ Arctostaphylos         : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Empetrum               : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Rhododendron           : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Chamaedaphne.calyculata: num  0 0 0 0 0 0 0 0 0 0 ...
 $ Vaccinium              : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Amorpha                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Dalea                  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Trifolium              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Melilotus              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Castanea               : num  0 0 0 0 0.00715 ...
 $ Fagus                  : num  0 0 0 0 0.00359 ...
 $ Quercus                : num  0.09733 0.00564 0 0 0.25066 ...
 $ Geranium               : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Ribes                  : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Hypericum              : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Iris                   : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Sisyrinchium           : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Itea                   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Carya                  : num  0 0 0 0 0.0387 ...
 $ Engelhardtia           : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Juglans                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Pterocarya             : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Stachys                : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Lycopus                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Mentha                 : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Lythrum                : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Magnolia               : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Liriodendron           : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Tilia                  : num  0 0 0 0 0 ...
 $ Waltheria              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Sphaeralcea            : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Fraxinus               : num  0 0 0 0 0 ...
 $ Osmanthus              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Epilobium              : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Abies                  : num  0.0863 0.0909 0.16 0.0538 0 ...
 $ Larix                  : num  0.0692 0 0 0 0 ...
 $ Picea                  : num  0.15199 0.75481 0.56231 0.25602 0.00215 ...
 $ Tsuga                  : num  0.00853 0 0 0 0.0043 ...
 $ Platanus               : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Polygonella            : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Polygonum              : num  0 0 0 0 0.00144 ...
 $ Eriogonum              : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Fagopyrum              : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Koenigia               : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Rumex.Oxyria           : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Anemone                : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Ranunculus             : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Thalictrum             : num  0 0 0 0 0.000719 ...
 $ Rhizophora             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Amelanchier            : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Dryas                  : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Geum                   : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Potentilla             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Sanguisorba            : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Spiraea                : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Prunus                 : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Cephalanthus           : num  0 0 0 0 0.0751 ...
 $ Galium                 : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Populus                : num  0 0 0 0 0.00571 ...
 $ Salix                  : num  0.04612 0.00102 0.00229 0.00679 0.00501 ...
 $ Comandra               : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Acer                   : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Sarcobatus             : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Symplocos              : int  0 0 0 0 0 0 0 0 0 0 ...
  [list output truncated]

rr # clean up the site/rownames pollen.6000.sites <- pollen.6000\(sites rownames(pollen.6000) <- pollen.6000\)sites pollen.6000 <- pollen.6000[,-1]

Richness, diversity, and evenness calculations

rr # calculate richness and diversity S.obs <- specnumber(pollen.6000) H <- diversity(pollen.6000, ) Simp <- diversity(pollen.6000, ‘simpson’) H_even <- H/log(S.obs)

OK, now examine how diversity changes across lat and long

rr # get site lat/longs meta <- read.delim(file=/pollen/All.site.data-withagemodel-finalv2.txt, sep=\t) site.longlats <- meta[match(pollen.6000.sites, meta$Handle), c(‘Longitude’, ‘Latitude’)] # simple relationships with latitude and longitude par(mfrow=c(2,2), mar=c(4,4,1,1)+0.1) plot(H~site.longlats\(Latitude, pch=16, xlab=\Latitude\) plot(S.obs~site.longlats\)Latitude, pch=16, xlab=) r plot(Simp~site.longlats\(Latitude, pch=16, xlab=\Latitude\) plot(H_even~site.longlats\)Latitude, pch=16, xlab=) r par(mfrow=c(2,2), mar=c(4,4,1,1)+0.1)

rr plot(H~site.longlats\(Longitude, pch=16, xlab=\Longitude\) plot(S.obs~site.longlats\)Longitude, pch=16, xlab=) r plot(Simp~site.longlats\(Longitude, pch=16, xlab=\Longitude\) plot(H_even~site.longlats\)Longitude, pch=16, xlab=)

Practice

Note: In the ‘data’ folder, you have similar pollen files for multiple time periods.

Questions:

  1. What else could you do with these data? Explore additional diversity analyses, either using these data for 6000 years BP, or by looking at the datasets for other times.

  2. Use the knowledge you’ve gained from today or previous modules in the course to extract information from other sites in the PaleobioDB or Neotoma and calculate diversity.

Part 5: SADs and RADs

One other common way to visualize the structure of communities is through species abundance distributions (SADs), and related rank abundance distributions (RADs). This is a way to visualize the differences in commonness and rarity among species, and can potentially be compared among communities. SADs/RADs have a long history in ecology, and the general pattern is that to be rare is common and to be common is rare. That is, very few species are highly abundant, and many more species have low abundances.

rr # this chunk uses the sads package vignette(‘sads_intro’)

Let’s revisit the small mammal data from Samwell Cave and answer the question: has the structure of the community changed through time? We’ll focus mostly on RADs.

rr # examine the two endpoints scpd1.oc <- octav(scpdSM[1,]) scpd14.oc <- octav(scpdSM[14,]) scpd1.oc

Object of class \octav\

rr scpd14.oc

Object of class \octav\

rr par(mfrow=c(4,4), mar=c(3,3,2,0)+0.1) for (i in 1:nrow(scpdSM)){ plot(rad(scpdSM[i,]), prop=F, xlab=\, ylab=\, xlim=c(1, 13), type=, pch=16) mtext(side=2, line=2, of Indiv, cex=0.5) mtext(side=3, line=0.5, paste0(=, ages[i]), cex=0.75) mtext(side=1, line=2, , cex=0.5) }

Question:

What do the figures above show us?

Alternate approach

McGill (2011, Ch. 9) identifies a few problems with simplistic visual comparisons of RADs that are visible in the figure above.

  1. Ranks can be difficult to deal with mathematically
  2. Because richness varies among communities, it can be difficult to compare RADs across assemblages. It’s not such a huge deal with the Samwell Cave data, but would be a bigger issue with more disparity in richness.

He suggests instead using ECDFs (empirical cumulative density functions) instead.

rr par(mfrow=c(4,4), mar=c(3,3,2,0)+0.1) for (i in 1:nrow(scpdSM)){ plot(ecdf(scpdSM[i,]), xlab=\, ylab=\, xlim=c(1, 13), main=\, verticals=T, do.points=F, cex.axis=0.75) mtext(side=2, line=2, % of Species, cex=0.5) mtext(side=3, line=0.5, paste0(=, ages[i]), cex=0.75) mtext(side=1, line=2, % abundance, cex=0.5) }

Formal model fitting

It’s possible using the sads package (and also vegan, though the approaches differ) to fit various models to the SADs/RADs. There are quite a few different models to choose from, and different authors have postulated that different distributions are indicative of different types of communities. I’ve randomly chosen three: geometric (low diversity), Fisher’s log-series (medium diversity), and lognormal (high diversity).

rr # fit the models scpd1.geom <- fitsad(scpdSM[1,scpdSM[1,]>0], ‘geom’) scpd1.ls <- fitsad(scpdSM[1,scpdSM[1,]>0], ‘ls’) scpd1.lnorm <- fitsad(scpdSM[1,scpdSM[1,]>0], ‘lnorm’) # compare the fit of each model AICtab(scpd1.geom, scpd1.ls, scpd1.lnorm, base=TRUE)

            AIC  dAIC df
scpd1.ls    68.6  0.0 1 
scpd1.lnorm 74.3  5.7 2 
scpd1.geom  79.4 10.8 1 

rr # transform to appropriate class for plotting scpd1.geom.oc <- octavpred(scpd1.geom) scpd1.ls.oc <- octavpred(scpd1.ls) scpd1.lnorm.oc <- octavpred(scpd1.lnorm) # plot the three models against one another and the data plot(scpd1.oc) lines(scpd1.geom.oc, col=) r lines(scpd1.ls.oc, col=) lines(scpd1.lnorm.oc, col=) r legend(, c(, , ), lty=1, col=c(,, ))

LS0tCnRpdGxlOiAiQW5hbHl0aWNhbCBQYWxlb2Jpb2xvZ3kgVHV0b3JpYWxzIDIwMTgiCnN1YnRpdGxlOiAiRGl2ZXJzaXR5IGFuYWx5c2VzIC0gcmljaG5lc3MsIGRpdmVyc2l0eSwgZXZlbm5lc3MiCmF1dGhvcjogSmVzc2ljYSBCbG9pcwpkYXRlOiAiQXVndXN0IDEsIDIwMTggKGxhc3QgdXBkYXRlZDogT2N0b2JlciAyOSwgMjAxOCkiCm91dHB1dDoKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQojIFBhcnQgMTogSW50cm9kdWN0aW9uIHRvIGVzdGltYXRpbmcgYmlvbG9naWNhbCBkaXZlcnNpdHkKCiMjIyBXaGF0IGlzIHRoZSBnb2FsPyAgCgpPZnRlbiwgd2UgYXJlIGludGVyZXN0ZWQgaW4gZGVzY3JpYmluZyB0aGUgKnJpY2huZXNzKiBhbmQgc3RydWN0dXJlIG9yICpkaXZlcnNpdHkqIG9mIGFuIGFzc2VtYmxhZ2UuIEJ1dCBtb3JlIGltcG9ydGFudGx5LCB3ZSBhcmUgb2Z0ZW4gbW9yZSBpbnRlcmVzdGVkIGluIGNvbXBhcmluZyByaWNobmVzcyBhbmQgZGl2ZXJzaXR5IGFjcm9zcyBzcGFjZSBhbmQvb3IgdGltZSwgYnkgbWVyZ2luZyBkYXRhIGZyb20gbXVsdGlwbGUgc2l0ZXMgb3IgZnJvbSBkaWZmZXJlbnQgc2FtcGxpbmcgdW5pdHMgd2l0aGluIGEgc2l0ZS4gIAoKQnkgKnJpY2huZXNzKiwgd2UgbWVhbiB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBzcGVjaWVzIG9yIHRheG9ub21pYy9waHlsb2dlbmV0aWMvZnVuY3Rpb25hbCB1bml0cyBpbiB0aGUgYXNzZW1ibGFnZS4gIEJ5ICpkaXZlcnNpdHkqLCB3ZSB1c3VhbGx5IG1lYW4gc29tZSBhc3BlY3Qgb2YgdGhlIHN0cnVjdHVyZSBvZiB0aGUgYXNzZW1ibGFnZSAtIGEgY29tYmluYXRpb24gb2YgYm90aCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBlbGVtZW50cyBhcyB3ZWxsIGFzIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgdGhlIGRpZmZlcmVudCBlbGVtZW50cy4gCgpPdmVyYWxsLCBiaW9sb2dpY2FsIGRpdmVyc2l0eSBtZXRyaWNzIGNhbiBiZSBjaGFyYWN0ZXJpemVkIGFzOgoKMSkgUmljaG5lc3MgbWV0cmljcyA6IG51bWJlciBvZiBzcGVjaWVzCjIpIEV2ZW5uZXNzIG1ldHJpY3MgOiBjYXB0dXJlIHRoZSBkaXN0cmlidXRpb24gb2YgYWJ1bmRhbmNlIGFtb25nIHNwZWNpZXMKMykgRGl2ZXJzaXR5IG1ldHJpY3MgOiBjb21iaW5lcyBib3RoIHJpY2huZXNzIGFuZCBldmVubmVzcyAKNCkgRG9taW5hbmNlIG1ldHJpY3MgOiBzb21ld2hhdCB0aGUgaW52ZXJzZSBvZiBldmVubmVzcywgZm9jdXNlZCBvbiB0aGUgbW9zdCBjb21tb24gc3BlY2llcyAobm90IGNvdmVyZWQpCgpUb2RheSwgd2Ugd2lsbCBiZSBleHBsb3JpbmcgZGlmZmVyZW50IGFzcGVjdHMgb2YgZXN0aW1hdGluZyByaWNobmVzcyBhbmQgZGl2ZXJzaXR5LiBBIGdvb2QgcmVzb3VyY2UgZm9yIHRoaXMgdG9waWMsIGFuZCBvbmUgb24gd2hpY2ggSSBoYXZlIHJlbGllZCBoZWF2aWx5IGluIHRoaXMgbGVjdHVyZSAoaW4gYWRkaXRpb24gdG8gcGFja2FnZSB2aWduZXR0ZXMpLCBpcyB0aGUgYm9vayAiQmlvbG9naWNhbCBEaXZlcnNpdHkiIGJ5IE1hZ3VycmFuIGFuZCBNY0dpbGwgPGh0dHBzOi8vZ2xvYmFsLm91cC5jb20vYWNhZGVtaWMvcHJvZHVjdC9iaW9sb2dpY2FsLWRpdmVyc2l0eS05NzgwMTk5NTgwNjc1P2NjPXVzJmxhbmc9ZW4mPi4gIFRoaXMgYm9vayBtYXkgYmUgYXZhaWxhYmxlIHRocm91Z2ggeW91ciBpbnN0aXR1dGlvbmFsIGxpYnJhcnkuCgojIFBhcnQgMjogR2V0dGluZyBzdGFydGVkIHdpdGggUgoKV2Ugd2lsbCBuZWVkIHRvIGxvYWQgYWxsIHJlbGV2YW50IHBhY2thZ2UgCmBgYHtyfQojIHVuY29tbWVudCB0aGUgZm9sbG93aW5nIGxpbmUgaWYgeW91IGhhdmVuJ3QgaW5zdGFsbGVkIHRoZXNlIHBhY2thZ2VzIHlldAojIGluc3RhbGwucGFja2FnZXMoYygndmVnYW4nLCAnbmVvdG9tYScsICdkcGx5cicsICdzYWRzJywgJ2lORVhUJykpIAoKbGlicmFyeSgndmVnYW4nKQpsaWJyYXJ5KCduZW90b21hJykKbGlicmFyeSgnZHBseXInKQpsaWJyYXJ5KCdzYWRzJykKbGlicmFyeSgnaU5FWFQnKQpgYGAKCiMgUGFydCAzOiBEaXZlcnNpdHkgYW5hbHlzZXMgZm9yIGEgc2luZ2xlIHNpdGUgdGhyb3VnaCB0aW1lCgojIyMgRG93bmxvYWQgZGF0YSBmb3IgYSBzaW5nbGUgc2l0ZQoKTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBzZWFyY2ggZm9yIGEgc2luZ2xlIHNpdGUgaW4gdGhlIE5lb3RvbWEgUGFsZW9lY29sb2d5IERhdGFiYXNlIDxodHRwczovL3d3dy5uZW90b21hZGIub3JnLz4uIFdlJ2xsIGRvd25sb2FkIG1hbW1hbCBkYXRhIGZyb20gb25lIHNpdGUgKGxhdGUgUXVhdGVybmFyeSBjYXZlIGRlcG9zaXQpIGluIG5vcnRoZXJuIENhbGlmb3JuaWEsIFNhbXdlbGwgQ2F2ZSBQb3Bjb3JuIERvbWUsIGFsb25nIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgYWdlcyBvZiB0aGUgc2FtcGxlZCB1bml0cy4KYGBge3J9CnNhbXdlbGxfc2l0ZSA8LSBnZXRfc2l0ZShzaXRlbmFtZT0iU2Ftd2VsbCBDYXZlIikgI3RoZXJlJ3Mgb25lIHNpdGUgaW4gdGhlIGRhdGFiYXNlIHRoYXQgbWF0Y2hlcyB0aGlzCnNhbXdlbGxfZGF0YXNldHMgPC0gZ2V0X2RhdGFzZXQoc2Ftd2VsbF9zaXRlW1sxXV0pICMgdGhpcyBzZWFyY2ggbGlzdHMgYWxsIGRhdGFzZXRzIGFzc29jaWF0ZWQgd2l0aCBTYW13ZWxsIENhdmUuIFRoZXJlIGFyZSA3IGRpZmZlcmVudCBkYXRhc2V0cyBmb3IgdGhlIHNpdGU6IDQgY29udGFpbmluZyB2ZXJ0ZWJyYXRlIGZhdW5hbCBpbmZvcm1hdGlvbiBhbmQgMyBjb250YWluaW5nIGdlb2Nocm9ub2xvZ2ljIGluZm9ybWF0aW9uLiAKYnJvd3NlKHNhbXdlbGxfZGF0YXNldHMpICMgTm90ZSB0aGF0IHRoaXMgb3BlbnMgYSBuZXcgd2luZG93IGluIHlvdXIgYnJvd3NlcgoKIyBEb3dubG9hZCBpbmZvIGZvciBqdXN0IHRoZSBsYXN0IGRhdGFzZXQsIDE0MjYyLiAKc2NwZF9kYXRhc2V0IDwtIGdldF9kYXRhc2V0KHNhbXdlbGxfc2l0ZVtbMV1dKSQnMTQyNjInCnNjcGRfZG93bmxvYWQgPC0gZ2V0X2Rvd25sb2FkKHNjcGRfZGF0YXNldCkKCiMgRXh0cmFjdCB0aGUgY291bnQgZGF0YSBhbmQgdGhlIHNhbXBsZSBhZ2VzCnNjcGRGYXVuYSA8LSBjb3VudHMoc2NwZF9kb3dubG9hZClbWzFdXQpzY3BkQWdlcyA8LSBhZ2VzKHNjcGRfZG93bmxvYWQpW1sxXV0KICAgCiMgc2F2ZSBhcyBSIG9iamVjdCBmb3IgbGF0ZXIgdXBsb2FkIGluIGNhc2Ugbm8gaW50ZXJuZXQgb3IgQVBJIG5vdCB3b3JraW5nCiMgc2F2ZShzY3BkRmF1bmEsIHNjcGRBZ2VzLCBmaWxlPSJkYXRhL3NjcGRPYmplY3RzLlJEYXRhIikKCiMgTm90ZTogRGF0YXNldCAxNDI2MSBjb250YWlucyB0aGUgdW5kZXJseWluZyByYWRpb2NhcmJvbiBkYXRlcyBmb3IgdGhlIHNpdGUsIGluIGNhc2UgeW91IHdhbnQgdG8gZXhhbWluZSB0aG9zZS4gWW91J2xsIG5lZWQgdG8gdW5jb21tZW50IHRoZSBuZXh0IHR3byBsaW5lcwojIHNjcGRfZ2VvY2hyb24gPC0gZ2V0X2dlb2Nocm9uKDE0MjYxKQojIHNjcGRfZ2VvY2hyb25bWzFdXSRnZW9jaHJvbgpgYGAKCiMjIyBDbGVhbiB1cCB0aGUgYXNzZW1ibGFnZS9zaXRlIGRhdGEKCk9LLCBub3cgdGhhdCB3ZSBoYXZlIHRoZSBiYXNpYyBkYXRhc2V0IGRvd25sb2FkZWQsIHdlIHdpbGwgbmVlZCB0byBjbGVhbiB1cCB0aGUgZGF0YS4gCgoqKlF1ZXN0aW9uOioqCgpXaGF0IGtpbmRzIG9mIGRhdGEgY2xlYW5pbmcgbWlnaHQgd2Ugd2FudCB0byBkbyBoZXJlPwoKSXQncyBvZnRlbiBoZWxwZnVsIHRvIGV4YW1pbmUgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YSB0byBhbnN3ZXIgdGhpcyBxdWVzdGlvbi4KYGBge3J9CiMgZXhhbWluZSB0aGUgZmluYWwgZG93bmxvYWRlZCBmaWxlCnN0cihzY3BkRmF1bmEpICMgYW5vdGhlciBwb3NzaWJsZSB3YXkgdG8gZXhhbWluZSB0aGUgZGF0YTogZ2xpbXBzZShzY3BkRmF1bmEpCmhlYWQoc2NwZEZhdW5hKSAKYGBgCgpTdGFydCBjbGVhbmluZyB1cCB0aGUgZGF0YSBmaWxlcy4KYGBge3J9CiMgV2hhdCBhcmUgdGhlIHJvd25hbWVzIHNob3dpbmc/ICAKIyBMZXQncyByZXBsYWNlIHRoZSBzYW1wbGUgSUQgaW4gdGhlIGZhdW5hIG9iamVjdCAocm93bmFtZXMpIHdpdGggdGhlIGFnZXMKIyBidXQgb25seSBkbyB0aGlzIGlmIHRoZSBzYW1wbGUgSURzIG1hdGNoIGFjcm9zcyBvYmplY3RzCmFnZXMgPC0gc2NwZEFnZXMkYWdlCmlmIChhbGwocm93bmFtZXMoc2NwZEZhdW5hKSA9PSBzY3BkQWdlcyRzYW1wbGUuaWQpKXsKICByb3duYW1lcyhzY3BkRmF1bmEpIDwtIGFnZXMKfQoKIyBzZXQgdGhlIG5hbWVzIG9mIHRoZSBzbWFsbCBtYW1tYWwgZ2VuZXJhIG9mIGludGVyZXN0CiMgbm90ZTogdGhpcyBpcyBhIGNsdW5reSB3b3JrYXJvdW5kIC0gaWRlYWxseSB3ZSdkIGJlIGFibGUgdG8gaGFybW9uaXplIHRheG9ub215IHVzaW5nIHRoZSBkYXRhYmFzZS9BUEkgdG9vbHMsIGJ1dCB0aGV5IGFyZW4ndCBhcyBnb29kIGluIE5lb3RvbWEgYXMgaW4gUEJEQiBiZWNhdXNlIG9mIHRoZSB3YXkgdGF4b25vbXkgaXMgaGFuZGxlZApzbV9nZW51cyA8LSBjKCJTY2FwYW51cyIsICJNaWNyb3R1cyIsICJOZW90b21hIiwgIlBlcm9teXNjdXMiLCAiU29yZXgiLCAiU3Blcm1vcGhpbHVzIiwgIlRhbWlhcyIsICJUYW1pYXNjaXVydXMiLCAiVGhvbW9teXMiLCAiQXJib3JpbXVzIiwgIlJlaXRocm9kb250b215cyIsICJTY2l1cnVzIiwgIkdsYXVjb215cyIsICJNeW9kZXMiLCAiQXBsb2RvbnRpYSIpCgojIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCB0aGUgbWVyZ2VkIGRhdGEKc2NwZFNNIDwtIG1hdHJpeChucm93PW5yb3coc2NwZEZhdW5hKSwgbmNvbD1sZW5ndGgoc21fZ2VudXMpKQoKZm9yIChpIGluIDE6bGVuZ3RoKHNtX2dlbnVzKSl7CiAgY29scyA8LSBncmVwKHNtX2dlbnVzW2ldLCBjb2xuYW1lcyhzY3BkRmF1bmEpKQoKICBpZiAobGVuZ3RoKGNvbHMpPT0xKXsKICAgIHNjcGRTTVssaV0gPC0gc2NwZEZhdW5hWyxjb2xzXQogIH0KICBpZiAobGVuZ3RoKGNvbHMpID4gMSl7CiAgICBzY3BkU01bLGldIDwtIHJvd1N1bXMoc2NwZEZhdW5hWyxjb2xzXSkKICB9CiAgCn0KCiMgY2xlYW4gdXAgZGF0YWZyYW1lCmNvbG5hbWVzKHNjcGRTTSkgPC0gc21fZ2VudXMKcm93bmFtZXMoc2NwZFNNKSA8LSByb3duYW1lcyhzY3BkRmF1bmEpCnNhdmUoc2NwZFNNLCBmaWxlPSJkYXRhL3NjcGRGYXVuYV9jbGVhbmVkLlJEYXRhIikKYGBgCgojIyMgUmljaG5lc3MgYW5hbHlzZXMKCioqUmFyZWZhY3Rpb24tYmFzZWQgZXN0aW1hdGVzKioKCkZpcnN0LCBsZXQncyBjYWxjdWxhdGUgcmF3IHJpY2huZXNzLCBmb3IgZWFjaCBzYW1wbGUgdGhyb3VnaCB0aW1lCmBgYHtyfQojIHdlIGNhbiBwcmFjdGljZSBidWlsZGluZyBvdXIgb3duIGZ1bmN0aW9ucyB0byBjb3VudCB1cCB0aGUgc3BlY2llcwpjb3VudEZjbiA8LSBmdW5jdGlvbihkZil7CiAgY291bnQgPC0gbGVuZ3RoKHdoaWNoKGRmPjApKQogIHJldHVybihjb3VudCkKfSAKcmF3LlMgPC0gYXBwbHkoc2NwZFNNLCAxLCBjb3VudEZjbikKIyBvciB5b3UgY2FuIGRvIHRoZSBzYW1lIGNhbGN1bGF0aW9uIHVzaW5nIGEgYnVpbHQtaW4gZnVuY3Rpb24gKHNwZWNudW1iZXIpIGluIHZlZ2FuCnNwZWNudW1iZXIoc2NwZFNNKQpgYGAKCkhvd2V2ZXIsIHdlIGtub3cgdGhlc2UgYXJlIGZvc3NpbCBkYXRhIGFuZCAoZXZlbiBpZiB0aGV5IHdlcmVuJ3QhKSBzYW1wbGluZyBlZmZvcnQgbWF5IGhhdmUgdmFyaWVkIHRocm91Z2ggdGltZSBhbmQgYWNyb3NzIHNhbXBsZXMuIGllLCB0aGUgdG90YWwgc2FtcGxlIHNpemUgKE4pIG9mIGVhY2ggc2FtcGxlIChzdHJhdHVtKSB2YXJpZXMgc3Vic3RhbnRpYWxseSwgYXMgY2FuIGJlIHNlZW4gYnkgZXhhbWluaW5nIHRoZSByYW5nZSBvZiB0b3RhbCBOLgpgYGB7cn0KcmFuZ2Uocm93U3VtcyhzY3BkU00pKQptaW5OIDwtIG1pbihyb3dTdW1zKHNjcGRTTSkpCmBgYAoKU28gb25lIGFwcHJvYWNoIGlzIHJhcmVmeSBlYWNoIGFzc2VtYmxhZ2UgZG93biB0byB0aGUgbWluaW11bSBOIHdoZW4gY2FsY3VsYXRpbmcgcmljaG5lc3MuIFRoaXMgZWZmZWN0aXZlbHkgYW5zd2VyczogV2hhdCBpcyB0aGUgZXhwZWN0ZWQgcmljaG5lc3Mgb2YgYW4gYXNzZW1ibGFnZSBpZiB3ZSBzYW1wbGVkIHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBhcyB3ZXJlIG9ic2VydmVkIGluIHNvbWUgb3RoZXIgYXNzZW1ibGFnZT8gIFlvdSBkaWQgdGhpcyBtYW51YWxseSBpbiBTZXRoJ3Mgc2VjdGlvbiwgYW5kIHRoZW4gaGUgYWxzbyBpbnRyb2R1Y2VkIHlvdSB0byB0aGUgZnVuY3Rpb24gKnJhcmVmeSogaW4gdGhlICp2ZWdhbiogcGFja2FnZS4gKnJhcmVmeSogImdpdmVzIHRoZSBleHBlY3RlZCBzcGVjaWVzIHJpY2huZXNzIGluIHJhbmRvbSBzdWJzYW1wbGVzIG9mIHNpemUgc2FtcGxlIGZyb20gdGhlIGNvbW11bml0eSIgKGZyb20gaGVscCBkb2MpIGFuZCBwZXJmb3JtcyB0aGlzIGZvciBhbGwgc2FtcGxlcy9hc3NlbWJsYWdlcyBpbiB0aGUgY29tbXVuaXR5IG1hdHJpeC4KYGBge3J9CnJpY2huZXNzIDwtIHJhcmVmeShzY3BkU00sIHNhbXBsZT1taW5OLCBzZT1UKSAjIGJlY2F1c2UgSSBzcGVjaWZpZWQgKnNlPVQqLCB0aGlzIGZ1bmN0aW9uIG91dHB1dHMgYm90aCBTIGFuZCBzZQpTIDwtIHJpY2huZXNzWzEsXQpTLnNlIDwtIHJpY2huZXNzWzIsXQoKIyBwbG90IHRoZSByZXN1bHQgdGhyb3VnaCB0aW1lIHVzaW5nIGJhc2UgUiBwbG90dGluZyBmdW5jdGlvbgpwbG90KFMgfiBhZ2VzLCB0eXBlPSJsIiwgeGxpbT1jKDIxMDAwLCAwKSwgeWxpbT1jKDAsIGZsb29yKG1heChTK1Muc2UpKSsxKSwgeGxhYj0iQWdlIChjYWwgQlApIiwgeWxhYj1leHByZXNzaW9uKCdSaWNobmVzcycgJSstJSAnc2UnKSkKI2Fycm93cyhhZ2VzLCBTK1Muc2UsIGFnZXMsIFMtUy5zZSwgY29kZT0zLCBsZW5ndGg9MC4xLCBhbmdsZT05MCkKc3VwcHJlc3NXYXJuaW5ncyhhcnJvd3MoYWdlcywgUytTLnNlLCBhZ2VzLCBTLVMuc2UsIGNvZGU9MywgbGVuZ3RoPTAuMSwgYW5nbGU9OTApKSAKCiMgTm90ZTogdXNlIHN1cHByZXNzV2FybmluZ3Mgd2l0aCBjYXV0aW9uLiAgSSBhZGRlZCB0aGUgc3VwcHJlc3NXYXJuaW5ncyB0YWcgc28gdGhhdCB0aGUgb25seSB0aGluZyBvdXRwdXQgaXMgdGhlIHBsb3QuIEJ1dCBJIG9ubHkgZGlkIHRoaXMgYWZ0ZXIgSSBjb25maXJtZWQgdGhhdCB0aGUgd2FybmluZyBtZXNzYWdlIHdhcyBvay4gU3dpdGNoIHRoZSBhcnJvd3MgbGluZXMgdGhhdCBhcmUgY29tbWVudGVkL3VuY29tbWVudGVkIGFuZCByZS1ydW4gdGhlIHBsb3Qgd2l0aCB0aGF0IGxpbmUgb2YgY29kZSBmb3IgYXJyb3dzIHRvIHZpZXcgdGhlIHdhcm5pbmcgYW5kIGRlY2lkZSBmb3IgeW91cnNlbGYgd2hldGhlciBpdCBzaG91bGQgYmUgc3VwcHJlc3NlZCBvciBub3QuCmBgYAoKTGV0J3MgY29tcGFyZSByYXJlZmllZCB0byByYXcgcmljaG5lc3MsIGZvciBlYWNoIHNhbXBsZSB0aHJvdWdoIHRpbWUKYGBge3J9CnBsb3QocmF3LlMgfiBhZ2VzLCB0eXBlPSJsIiwgeGxpbT1jKDIxMDAwLCAwKSwgeWxpbT1jKDAsIG1heChyYXcuUykrMSksIGx0eT0yLCBjb2w9ImdyYXkiLCB4bGFiPSJBZ2UgKGNhbCBCUCkiLCB5bGFiPSdSaWNobmVzcycpCmxpbmVzKFMgfiBhZ2VzLCB0eXBlPSJsIikKYXJyb3dzKGFnZXMsIFMrUy5zZSwgYWdlcywgUy1TLnNlLCBjb2RlPTMsIGxlbmd0aD0wLjEsIGFuZ2xlPTkwKQpgYGAKCldlIGNhbiBhbHNvIGNvbXBhcmUgdGhlIHNhbXBsaW5nIGN1cnZlcyB1c2luZyBmdW5jdGlvbiAqcmFyZWN1cnZlKi4gVGhpcyBncmFicyByYW5kb20gc2FtcGxlcyBvZiBkaWZmZXJlbnQgbnVtYmVycyBvZiBpbmRpdmlkdWFscyBpbiBhIHN0ZXAtd2lzZSBmdW5jdGlvbiwgdGhlbiBjYWxjdWxhdGVzIHJpY2huZXNzIGZvciBlYWNoIHNhbXBsZS4KYGBge3J9CiMgc2V0IGNvbG9ycywgZnJvbSBjb29sIGZvciB0aGUgb2xkZXIgKExHTSkgdGltZXMgYW5kIHJlZCBmb3IgdGhlIHdhcm1lciAoSG9sb2NlbmUpIHRpbWVzCmFnZUNvbG9ycyA8LSByYWluYm93KGxlbmd0aChhZ2VzKSwgc3RhcnQ9MCwgZW5kPTQvNikKCnJhcmVjdXJ2ZShzY3BkU00sIGNvbD1hZ2VDb2xvcnMpCmBgYAoKKipFeHRyYXBvbGF0aW9uLWJhc2VkIGVzdGltYXRlcyBvZiByaWNobmVzcyoqCgpSYXJlZmFjdGlvbiBjYWxjdWxhdGVzIHRoZSBleHBlY3RlZCByaWNobmVzcyBpZiB0aGUgc2FtZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgd2VyZSBzYW1wbGVkIGFjcm9zcyBkaWZmZXJlbnQgc2FtcGxlcy4gSG93ZXZlciwgdGhlcmUgYXJlIG90aGVyIHdheXMgdG8gZXN0aW1hdGUgcmljaG5lc3MgYW5kIGNvbXBhcmUgYW1vbmcgc2FtcGxlcy4gQW1vbmcgdGhlIG1vcmUgY29tbW9uIGFsdGVybmF0aXZlcyB0byByYXJlZmFjdGlvbiBhcmUgdGhlIENoYW8gYW5kIEFDRSAoQWJ1bmRhbmNlLWJhc2VkIENvdmVyYWdlIEVzdGltYXRvcikgZXN0aW1hdG9ycyBvZiByaWNobmVzcy4gTGV0J3MgZmlyc3QgY2FsY3VsYXRlIHRoZW0sIGFuZCB0aGVuIGRpc2N1c3MuCgpgYGB7cn0KP2VzdGltYXRlUiAjIHJlYWQgbW9yZSBhYm91dCB0aGlzIGZ1bmN0aW9uLCBhbmQgaG93IEFDRSBhbmQgQ2hhbzEgYXJlIGNhbGN1bGF0ZWQKYWx0X3JpY2huZXNzIDwtIGVzdGltYXRlUihzY3BkU00pCgojIEJpbmQgYWxsIHJpY2huZXNzIGVzdGltYXRlcyB0b2dldGhlciBhbmQgY29tcGFyZToKcmljaG5lc3NfYWxsIDwtIHJiaW5kKGFsdF9yaWNobmVzcywgcmljaG5lc3MpCgojIHBsb3QgdGhlbSBhZ2FpbnN0IG9uZSBhbm90aGVyCnkubWF4IDwtIGZsb29yKG1heChyaWNobmVzc19hbGwpKSsxICMgc2V0IHkgbWF4IGZvciBwbG90dGluZyAKCm1haW5Fc3RpbWF0ZXMgPC0gYygnUy5vYnMnLCAnUy5jaGFvMScsICdTLkFDRScsICdTJykgCnBsb3RSb3dzIDwtIG1hdGNoKG1haW5Fc3RpbWF0ZXMsIHJvd25hbWVzKHJpY2huZXNzX2FsbCkpCnBsb3RDb2xzIDwtIGMoImJsYWNrIiwgImJsdWUiLCAiZ3JlZW4iLCAicmVkIikKICAKaT0xCnBsb3QocmljaG5lc3NfYWxsW3Bsb3RSb3dzW2ldLF0gfiBhZ2VzLCB0eXBlPSJsIiwgeWxpbT1jKDAsIHkubWF4KSwgeGxpbT1jKDIxMDAwLCAwKSwgeGxhYj0iQWdlIChjYWwgQlApIiwgeWxhYj0iUmljaG5lc3MiLCBjb2w9cGxvdENvbHNbaV0pCgpmb3IgKGkgaW4gMjpsZW5ndGgocGxvdFJvd3MpKXsKICAgIGxpbmVzKHJpY2huZXNzX2FsbFtwbG90Um93c1tpXSxdIH4gYWdlcywgY29sPXBsb3RDb2xzW2ldKQp9CmxlZ2VuZCgiYm90dG9tbGVmdCIsIGxlZ2VuZD1tYWluRXN0aW1hdGVzLCBsdHk9MSwgY29sPXBsb3RDb2xzLCBidHk9Im4iLCBjZXg9MC43NSkKYGBgCgoqKkRpc2N1c3Npb24qKgoKWW91IGNhbiBzZWUgdGhhdCB0aGVzZSB0d28gYXBwcm9hY2hlcyAocmFyZWZhY3Rpb24gdnMgZXh0cmFwb2xhdGlvbikgcHJvZHVjZSBmdW5kYW1lbnRhbGx5IGRpZmZlcmVudCBlc3RpbWF0ZXMgb2YgdGhlIHRyZW5kIG9mIHNwZWNpZXMgcmljaG5lc3MgdGhyb3VnaCB0aW1lLiAgSW5kaXZpZHVhbC1iYXNlZCByYXJlZmFjdGlvbiAoUykgc2hvd3MgYSB0cmVuZCB0b3dhcmRzIGxvd2VyIHJpY2huZXNzIGZyb20gdGhlIFBsZWlzdG9jZW5lIHRvIHRoZSBIb2xvY2VuZSwgd2hlcmVhcyBBQ0UgYW5kIENoYW8xIGVzdGltYXRlcyBzaG93IGEgdHJlbmQgdG93YXJkcyBoaWdoZXIgcmljaG5lc3MgZnJvbSB0aGUgUGxlaXN0b2NlbmUgdG8gdGhlIEhvbG9jZW5lLiAgCgpTbyB3aGF0J3MgdGhlIGRpZmZlcmVuY2U/ICBJbmRpdmlkdWFsLWJhc2VkIHJhcmVmYWN0aW9uIChTKSBlc3RpbWF0ZXMgZXhwZWN0ZWQgcmljaG5lc3MgZ2l2ZW4gYSBzdWJzYW1wbGUgb2YgbiBpbmRpdmlkdWFscyBmcm9tIHRoZSBhc3NlbWJsYWdlLiBJdCdzIGEgc2ltcGxlIGZvcm0gb2Ygc3RhbmRhcmRpemF0aW9uIHNvIHRoYXQgZGlmZmVyZW50IHNhbXBsZXMgYXJlIGNvbXBhcmFibGUuIEluIHRoaXMgY2FzZSwgbiBpcyBzYW1wbGVkIGF0IHRoZSBtaW5pbXVtIE4gb2JzZXJ2ZWQgYW1vbmcgdGhlIHNhbXBsZXMgKE49MTMwKS4gIEFuZCBzaW5jZSBuIGlzIGdlbmVyYWxseSBsb3dlciB0aGFuIHRoZSB0b3RhbCBOIHNhbXBsZWQsIGl0J3MgcmVhbGx5IGFuIHVuZGVyZXN0aW1hdGUgb2Ygb24tdGhlLWdyb3VuZCByaWNobmVzcy4KCk9uIHRoZSBvdGhlciBoYW5kLCBDaGFvMSBhbmQgQUNFIGVzdGltYXRlIHRoZSBhc3ltcHRvdGljIHJpY2huZXNzIGVzdGltYXRlcy4gaWUsIHRoZXkgYm90aCB0cnkgdG8gZXh0cmFwb2xhdGUgYmV5b25kIHRoZSBzYW1wbGVkIGluZGl2aWR1YWxzIHRvIGZpZ3VyZSBvdXQgdGhlIGV4cGVjdGVkIHJpY2huZXNzIGlmIHRoZSBhc3NlbWJsYWdlIHdhcyBzYW1wbGVkIGNvbXBsZXRlbHkuIFRoZXkgZm9jdXMgaW4gcGFydGljdWxhciBvbiBpbmZvcm1hdGlvbiBpbiB0aGUgZGV0ZWN0ZWQgcmFyZSBzcGVjaWVzIChzaW5nbGV0b25zLCBldGMpIHRvIGVzdGltYXRlIHVuZGV0ZWN0ZWQgc3BlY2llcy4gCgpDaGFvMSBhbmQgQUNFIGhhdmUgYmVlbiBzaG93biB0byBwZXJmb3JtIGJldHRlciB0aGFuIG90aGVyIGVzdGltYXRvcnMgaW4gdmFyaW91cyBzdHVkaWVzLiBUaGV5IGFyZSBhbHNvIHNpbWlsYXIgdG8gKG9yIGZ1bmRhbWVudGFsbHkgdGhlIHNhbWUgYXMpIFNRUy4gQSByZWNlbnQgc3R1ZHkgKENsb3NlIGV0IGFsLiAyMDE4KSBleGFtaW5lZCBkaWZmZXJlbmNlcyBhbW9uZyByaWNobmVzcyBlc3RpbWF0b3JzIGFuZCBmb3VuZCAic2FtcGxpbmcgaW4gdGhlIHRldHJhcG9kIGZvc3NpbCByZWNvcmQgaXMgZ2VuZXJhbGx5IG5vdCB5ZXQgZ29vZCBlbm91Z2ggdG8gdXNlIGV4dHJhcG9sYXRvcnMgdW5sZXNzIHRoZXkgYXJlIGFwcGxpZWQgd2l0aGluIGEgcmFyZWZ54oCQYW5k4oCQZXh0cmFwb2xhdGUgcHJvdG9jb2wgb2YgdGhlIGtpbmQgdXNlZCBpbiBvdXIgc2ltdWxhdGlvbiBleHBlcmltZW50cyIgYW5kICJJbiBwYXJ0aWN1bGFyLCByYXJlZnlpbmcgZXh0cmFwb2xhdG9ycyB0byBlcXVhbCBjb3ZlcmFnZSBpcyB0aGUgYmVzdCB3YXkgdG8gcmVtb3ZlIGNvbmZvdW5kaW5nIGVmZmVjdHMgb2YgYW1vbmfigJBzYW1wbGUgdmFyaWF0aW9uIGluIGV2ZW5uZXNzLCBhIHByb2JsZW0gdGhhdCBhZmZlY3RzIGFsbCByaWNobmVzcyBlc3RpbWF0b3JzIHdoZW4gc2FtcGxpbmcgaXMgY29tcGFyYXRpdmVseSBsaW1pdGVkIi4gVGhlIHBhY2thZ2UgKmlORVhUKiBpbXBsZW1lbnRzIHRoaXMgcmFyZWZ5aW5nIGV4dHJhcG9sYXRvcnMgZm9yIENoYW8xLCBzbyBsZXQncyBkbyBhIHF1aWNrIHRvdXIgdGhyb3VnaCB0aGF0IHBhY2thZ2UuCgpgYGB7cn0KIyB0aGlzIGNodW5rIHVzZXMgdGhlIGlOZXh0IHBhY2thZ2UKdmlnbmV0dGUoIkludHJvZHVjdGlvbiIsIHBhY2thZ2U9ImlORVhUIikKCmlOZXh0UmljaG5lc3MgPC0gaU5FWFQodChzY3BkU00pKSAKIyBOb3RlIDE6IHdlIGhhZCB0byB0cmFuc3Bvc2UgdGhlIGNvbW11bml0eSBtYXRyaXgKIyBOb3RlIDI6IHRoaXMgY2FsY3VsYXRlcyBub3QganVzdCByaWNobmVzcywgYnV0IGFsc28gU2hhbm5vbiBhbmQgU2ltcHNvbiBkaXZlcnNpdGllcy4KCiMgWW91IGNhbiBhbHNvIHJhcmVmeSB3aXRoaW4gaU5FWFQgdXNpbmcgZXN0aW1hdGVECkRfbWluTiA8LSBlc3RpbWF0ZUQodChzY3BkU00pLCBkYXRhdHlwZT0iYWJ1bmRhbmNlIiwgYmFzZT0ic2l6ZSIsIGxldmVsPU5VTEwpIApEX21pbk4KIyBOb3RlIDE6IFNDID0gc2FtcGxlIGNvdmVyYWdlLCBxRCBpcyB0aGUgZXN0aW1hdGUgd2l0aCBsb3dlciBhbmQgdXBwZXIgY29uZmlkZW5jZSBsZXZlbHMKIyBOb3RlIDI6IFJpY2huZXNzIGVzdGltYXRlcyBoZXJlIGFyZSB0aGUgc2FtZSBhcyB1c2luZyAqcmFyZWZ5KiBpbiB2ZWdhbi4gZS5nLiwgY29tcGFyZSB0aGUgZm9sbG93aW5nOgpEX21pbk5bd2hpY2goRF9taW5OJG9yZGVyID09IDApLF0kcUQKcmljaG5lc3NbMSxdCmBgYAoKUGxvdCB0aGUgQ2hhbyBlc3RpbWF0b3JzCmBgYHtyfQpnZ2lORVhUKGlOZXh0UmljaG5lc3MpCmdnaU5FWFQoaU5leHRSaWNobmVzcywgdHlwZT0xLCBmYWNldC52YXI9InNpdGUiKQpnZ2lORVhUKGlOZXh0UmljaG5lc3MsIHR5cGU9MikKYGBgCgojIyMgT3RoZXIgZGl2ZXJzaXR5IG1lYXN1cmVzCgpPSywgdXAgdG8gbm93IHdlJ3ZlIGp1c3QgYmVlbiBjb3VudGluZyB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgaW4gZGlmZmVyZW50IHdheXMuICBUaGUgb3RoZXIgYXNwZWN0IG9mIGFzc2VtYmxhZ2VzIGlzIHRoZWlyIGFidW5kYW5jZSBzdHJ1Y3R1cmUgLSBob3cgYWJ1bmRhbmNlIHZhcmllcyBhbW9uZyB0aGUgZGlmZmVyZW50IHNwZWNpZXMgaW4gdGhlIGRlcG9zaXQuCgoqKkRpdmVyc2l0eSoqCgpUaGVyZSBhcmUgc2V2ZXJhbCBjb21tb24gZGl2ZXJzaXR5IG1lYXN1cmVzLCB3aGljaCBjb21iaW5lIGJvdGggcmljaG5lc3MgYW5kIGV2ZW5uZXNzLiAgSSB0aGluayBpdCdzIGhlbHBmdWwgdG8gdmlldyB0aGUgY2FsY3VsYXRpb25zIGZvciB0aGVzZSBieSBsb29raW5nIGF0IG9uZSBvZiB0aGUgdmVnYW4gdmlnbmV0dGVzCmBgYHtyfQp2aWduZXR0ZSgiZGl2ZXJzaXR5LXZlZ2FuIikgIyBub3RlOiB0aGlzIG9wZW5zIGEgcGRmCgpIIDwtIGRpdmVyc2l0eShzY3BkU00sIGluZGV4PSJzaGFubm9uIikKU2ltcCA8LSBkaXZlcnNpdHkoc2NwZFNNLCBpbmRleD0ic2ltcHNvbiIpCmBgYAoKUHJhY3RpY2UgY2FsY3VsYXRpbmcgU2hhbm5vbiBvbiB5b3VyIG93bgpgYGB7cn0KIyBTaGFubm9uCnBpLlNDUEQgPC0gc2NwZFNNL3Jvd1N1bXMoc2NwZFNNKQpwaS5TQ1BEeGxvZ3BpIDwtIHBpLlNDUEQgKiBsb2cocGkuU0NQRCkKc3Vtc19zaGFuIDwtIHJvd1N1bXMocGkuU0NQRHhsb2dwaSwgbmEucm09VCkKSF9jYWxjIDwtIC1zdW1zX3NoYW4KYWxsKEg9PUhfY2FsYykKCiMgU2ltcHNvbgpwaS5TQ1BEMiA8LSBwaS5TQ1BEXjIKc3Vtc19zaW1wIDwtIHJvd1N1bXMocGkuU0NQRDIsIG5hLnJtPVQpClNpbXBfY2FsYyA8LSAxLXN1bXNfc2ltcAphbGwoU2ltcD09U2ltcF9jYWxjKQpgYGAKCioqRXZlbm5lc3MqKgoKWW91IHdlcmUgaW50cm9kdWNlZCB0byBldmVubmVzcyBpcyBTZXRoJ3MgbGVjdHVyZS4gVGhlcmUgYXJlbid0IGdvb2QgYnVpbHQtaW4gZnVuY3Rpb25zIGZvciBjYWxjdWxhdGluZyBldmVubmVzcyAodGhhdCBJIGtub3cgb2YpLCBidXQgUGllbG91J3MgKG9yIFNoYW5ub24pIGV2ZW5uZXNzIGNhbiBiZSBkZXJpdmVkIGZyb20gU2hhbm5vbiBkaXZlcnNpdHkgKEgpLiAoSC9sbihTKSkuICBUaGUgaWRlYSB1bmRlcmx5aW5nIGJvdGggb2YgdGhlc2UgbWVhc3VyZXMgaXMgdGhhdCBpZiBkaXZlcnNpdHkgaW5jb3Jwb3JhdGVzIGJvdGggcmljaG5lc3MgYW5kIGV2ZW5uZXNzLCB0aGVuIGZhY3RvcmluZyBvdXQgcmljaG5lc3MgZnJvbSB0aGUgZGl2ZXJzaXR5IG1lYXN1cmVzIHNob3VsZCBsZWF2ZSB1cyB3aXRoIGV2ZW5uZXNzLgpgYGB7cn0KU2hhbl9ldmVuIDwtIEgvbG9nKHNwZWNudW1iZXIoc2NwZFNNKSkKU2ltcF9ldmVuIDwtIFNpbXAvbG9nKHNwZWNudW1iZXIoc2NwZFNNKSkKYGBgCgpMZXQncyBwbG90IHRoZXNlIHRocm91Z2ggdGltZQpgYGB7cn0KcGxvdENvbHMgPC0gYygiYmxhY2siLCAiYmx1ZSIsICAiZ3JlZW4iLCAicmVkIikKcGxvdChIfmFnZXMsIHR5cGU9ImwiLCB5bGltPWMoMCwgMiksIHhsaW09YygyMTAwMCwgMCksIHhsYWI9IkFnZSAoY2FsIEJQKSIsIHlsYWI9IlJpY2huZXNzIiwgY29sPXBsb3RDb2xzWzFdKQpsaW5lcyhTaW1wfmFnZXMsIGNvbD1wbG90Q29sc1syXSkKbGluZXMoU2hhbl9ldmVufmFnZXMsIGNvbD1wbG90Q29sc1szXSwgbHR5PTIpCmxpbmVzKFNpbXBfZXZlbn5hZ2VzLCBjb2w9cGxvdENvbHNbNF0sIGx0eT0yKQpsZWdlbmQoImJvdHRvbWxlZnQiLCBsZWdlbmQ9YygiU2hhbm5vbiIsICJTaW1wc29uIiwgIkV2ZW5uZXNzX1NoYW5ub24iLCAiRXZlbm5lc3NfU2ltcHNvbiIpLCBsdHk9YygxLDEsMiwyKSwgY29sPXBsb3RDb2xzLCBidHk9Im4iLCBjZXg9MC43NSkKYGBgCgpOb3RlOiB5b3UgY291bGQgYWxzbyBjYWxjdWxhdGUgU2hhbm5vbiBhbmQgU2ltcHNvbiB0aHJvdWdoIGlOZXh0IChhcyBhYm92ZSksIGFuZCBwcm9iYWJseSB1c2luZyBzZXZlcmFsIG90aGVyIHBhY2thZ2VzLgoKCiMgUGFydCA0OiBFeHRlbmRpbmcgdGhlc2UgYW5hbHlzZXMgdG8gbXVsdGlwbGUgc2l0ZXMKTGV0J3MgYXNrOiBIb3cgZG8gcmljaG5lc3MsIGV2ZW5uZXNzLCBhbmQgZGl2ZXJzaXR5IHZhcnkgYWNyb3NzIGxhdGl0dWRlIGFuZCBsb25naXR1ZGU/IFdlIHdpbGwgdXNlIGEgZGF0YXNldCBvZiBRdWF0ZXJuYXJ5IGZvc3NpbCBwb2xsZW4gZGF0YSBmcm9tIGVhc3Rlcm4gTm9ydGggQW1lcmljYSBmb3IgNjAwMCB5ZWFycyBiZWZvcmUgcHJlc2VudC4KCk5vdGUsIHRoaXMgaXMgbm90IGNvdW50IGRhdGEgLSB0aGUgZGF0YSBhcmUgcHJvdmlkZWQgYXMgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBlYWNoIHRheG9uIGF0IHRoZSBzaXRlIC0gc28gdGhlIHJhcmVmYWN0aW9uIGFuZCBleHRyYXBvbGF0aW9uIGVzdGltYXRvcnMgZG9uJ3Qgd29yay4gVGhleSBvbmx5IGFjY2VwdCBjb3VudCBkYXRhIC8gaW50ZWdlcnMuCgoqKkRhdGEgbG9hZGluZyBhbmQgcHJlcCoqCmBgYHtyfQoKIyBsb2FkIHRoZSBkYXRhIGFuZCBleGFtaW5lIHRoZSBzdHJ1Y3R1cmUKcG9sbGVuLjYwMDAgPC0gcmVhZC5jc3YoZmlsZT0iZGF0YS9wb2xsZW4vNjAwMC5pbnRlcnAuZGF0YV9jbGVhbl9zaXRlcy5jc3YiKQpzdHIocG9sbGVuLjYwMDApCgojIGNsZWFuIHVwIHRoZSBzaXRlL3Jvd25hbWVzCnBvbGxlbi42MDAwLnNpdGVzIDwtIHBvbGxlbi42MDAwJHNpdGVzCnJvd25hbWVzKHBvbGxlbi42MDAwKSA8LSBwb2xsZW4uNjAwMCRzaXRlcwpwb2xsZW4uNjAwMCA8LSBwb2xsZW4uNjAwMFssLTFdCmBgYAoKKipSaWNobmVzcywgZGl2ZXJzaXR5LCBhbmQgZXZlbm5lc3MgY2FsY3VsYXRpb25zKioKYGBge3J9CiMgY2FsY3VsYXRlIHJpY2huZXNzIGFuZCBkaXZlcnNpdHkKUy5vYnMgPC0gc3BlY251bWJlcihwb2xsZW4uNjAwMCkKSCA8LSBkaXZlcnNpdHkocG9sbGVuLjYwMDAsICJzaGFubm9uIikKU2ltcCA8LSBkaXZlcnNpdHkocG9sbGVuLjYwMDAsICdzaW1wc29uJykKSF9ldmVuIDwtIEgvbG9nKFMub2JzKQpgYGAKCk9LLCBub3cgZXhhbWluZSBob3cgZGl2ZXJzaXR5IGNoYW5nZXMgYWNyb3NzIGxhdCBhbmQgbG9uZwpgYGB7cn0KIyBnZXQgc2l0ZSBsYXQvbG9uZ3MKbWV0YSA8LSByZWFkLmRlbGltKGZpbGU9ImRhdGEvcG9sbGVuL0FsbC5zaXRlLmRhdGEtd2l0aGFnZW1vZGVsLWZpbmFsdjIudHh0Iiwgc2VwPSJcdCIpCnNpdGUubG9uZ2xhdHMgPC0gbWV0YVttYXRjaChwb2xsZW4uNjAwMC5zaXRlcywgbWV0YSRIYW5kbGUpLCBjKCdMb25naXR1ZGUnLCAnTGF0aXR1ZGUnKV0KCgojIHNpbXBsZSByZWxhdGlvbnNoaXBzIHdpdGggbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZQpwYXIobWZyb3c9YygyLDIpLCBtYXI9Yyg0LDQsMSwxKSswLjEpCnBsb3QoSH5zaXRlLmxvbmdsYXRzJExhdGl0dWRlLCBwY2g9MTYsIHhsYWI9IkxhdGl0dWRlIikKcGxvdChTLm9ic35zaXRlLmxvbmdsYXRzJExhdGl0dWRlLCBwY2g9MTYsIHhsYWI9IkxhdGl0dWRlIikKcGxvdChTaW1wfnNpdGUubG9uZ2xhdHMkTGF0aXR1ZGUsIHBjaD0xNiwgeGxhYj0iTGF0aXR1ZGUiKQpwbG90KEhfZXZlbn5zaXRlLmxvbmdsYXRzJExhdGl0dWRlLCBwY2g9MTYsIHhsYWI9IkxhdGl0dWRlIikKCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDQsNCwxLDEpKzAuMSkKcGxvdChIfnNpdGUubG9uZ2xhdHMkTG9uZ2l0dWRlLCBwY2g9MTYsIHhsYWI9IkxvbmdpdHVkZSIpCnBsb3QoUy5vYnN+c2l0ZS5sb25nbGF0cyRMb25naXR1ZGUsIHBjaD0xNiwgeGxhYj0iTG9uZ2l0dWRlIikKcGxvdChTaW1wfnNpdGUubG9uZ2xhdHMkTG9uZ2l0dWRlLCBwY2g9MTYsIHhsYWI9IkxvbmdpdHVkZSIpCnBsb3QoSF9ldmVufnNpdGUubG9uZ2xhdHMkTG9uZ2l0dWRlLCBwY2g9MTYsIHhsYWI9IkxvbmdpdHVkZSIpCgpgYGAKCiMjIyBQcmFjdGljZQpOb3RlOiBJbiB0aGUgJ2RhdGEnIGZvbGRlciwgeW91IGhhdmUgc2ltaWxhciBwb2xsZW4gZmlsZXMgZm9yIG11bHRpcGxlIHRpbWUgcGVyaW9kcy4KCioqUXVlc3Rpb25zOioqIAoKMS4gV2hhdCBlbHNlIGNvdWxkIHlvdSBkbyB3aXRoIHRoZXNlIGRhdGE/IEV4cGxvcmUgYWRkaXRpb25hbCBkaXZlcnNpdHkgYW5hbHlzZXMsIGVpdGhlciB1c2luZyB0aGVzZSBkYXRhIGZvciA2MDAwIHllYXJzIEJQLCBvciBieSBsb29raW5nIGF0IHRoZSBkYXRhc2V0cyBmb3Igb3RoZXIgdGltZXMuCgoyLiBVc2UgdGhlIGtub3dsZWRnZSB5b3UndmUgZ2FpbmVkIGZyb20gdG9kYXkgb3IgcHJldmlvdXMgbW9kdWxlcyBpbiB0aGUgY291cnNlIHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gZnJvbSBvdGhlciBzaXRlcyBpbiB0aGUgUGFsZW9iaW9EQiBvciBOZW90b21hIGFuZCBjYWxjdWxhdGUgZGl2ZXJzaXR5LgoKIyBQYXJ0IDU6IFNBRHMgYW5kIFJBRHMKT25lIG90aGVyIGNvbW1vbiB3YXkgdG8gdmlzdWFsaXplIHRoZSBzdHJ1Y3R1cmUgb2YgY29tbXVuaXRpZXMgaXMgdGhyb3VnaCBzcGVjaWVzIGFidW5kYW5jZSBkaXN0cmlidXRpb25zIChTQURzKSwgYW5kIHJlbGF0ZWQgcmFuayBhYnVuZGFuY2UgZGlzdHJpYnV0aW9ucyAoUkFEcykuIFRoaXMgaXMgYSB3YXkgdG8gdmlzdWFsaXplIHRoZSBkaWZmZXJlbmNlcyBpbiBjb21tb25uZXNzIGFuZCByYXJpdHkgYW1vbmcgc3BlY2llcywgYW5kIGNhbiBwb3RlbnRpYWxseSBiZSBjb21wYXJlZCBhbW9uZyBjb21tdW5pdGllcy4gU0FEcy9SQURzIGhhdmUgYSBsb25nIGhpc3RvcnkgaW4gZWNvbG9neSwgYW5kIHRoZSBnZW5lcmFsIHBhdHRlcm4gaXMgdGhhdCB0byBiZSByYXJlIGlzIGNvbW1vbiBhbmQgdG8gYmUgY29tbW9uIGlzIHJhcmUuICBUaGF0IGlzLCB2ZXJ5IGZldyBzcGVjaWVzIGFyZSBoaWdobHkgYWJ1bmRhbnQsIGFuZCBtYW55IG1vcmUgc3BlY2llcyBoYXZlIGxvdyBhYnVuZGFuY2VzLgoKYGBge3J9CiMgdGhpcyBjaHVuayB1c2VzIHRoZSBzYWRzIHBhY2thZ2UKdmlnbmV0dGUoJ3NhZHNfaW50cm8nKSAjIG5vdGU6IG9wZW5zIGEgcGRmCmBgYAoKTGV0J3MgcmV2aXNpdCB0aGUgc21hbGwgbWFtbWFsIGRhdGEgZnJvbSBTYW13ZWxsIENhdmUgYW5kIGFuc3dlciB0aGUgcXVlc3Rpb246IGhhcyB0aGUgc3RydWN0dXJlIG9mIHRoZSBjb21tdW5pdHkgY2hhbmdlZCB0aHJvdWdoIHRpbWU/IFdlJ2xsIGZvY3VzIG1vc3RseSBvbiBSQURzLgpgYGB7cn0KCiMgZXhhbWluZSB0aGUgdHdvIGVuZHBvaW50cwpzY3BkMS5vYyA8LSBvY3RhdihzY3BkU01bMSxdKQpzY3BkMTQub2MgPC0gb2N0YXYoc2NwZFNNWzE0LF0pCnNjcGQxLm9jCnNjcGQxNC5vYwoKcGFyKG1mcm93PWMoNCw0KSwgbWFyPWMoMywzLDIsMCkrMC4xKQpmb3IgKGkgaW4gMTpucm93KHNjcGRTTSkpewogIHBsb3QocmFkKHNjcGRTTVtpLF0pLCBwcm9wPUYsIHhsYWI9IiIsIHlsYWI9IiIsIHhsaW09YygxLCAxMyksIHR5cGU9ImIiLCBwY2g9MTYpCiAgbXRleHQoc2lkZT0yLCBsaW5lPTIsICJOdW1iZXIgb2YgSW5kaXYiLCBjZXg9MC41KQogIG10ZXh0KHNpZGU9MywgbGluZT0wLjUsIHBhc3RlMCgiVGltZT0iLCBhZ2VzW2ldKSwgY2V4PTAuNzUpCiAgbXRleHQoc2lkZT0xLCBsaW5lPTIsICJSYW5rIiwgY2V4PTAuNSkKfQpgYGAKCioqUXVlc3Rpb246KioKCldoYXQgZG8gdGhlIGZpZ3VyZXMgYWJvdmUgc2hvdyB1cz8KCioqQWx0ZXJuYXRlIGFwcHJvYWNoKioKCk1jR2lsbCAoMjAxMSwgQ2guIDkpIGlkZW50aWZpZXMgYSBmZXcgcHJvYmxlbXMgd2l0aCBzaW1wbGlzdGljIHZpc3VhbCBjb21wYXJpc29ucyBvZiBSQURzIHRoYXQgYXJlIHZpc2libGUgaW4gdGhlIGZpZ3VyZSBhYm92ZS4gIAoKMSkgUmFua3MgY2FuIGJlIGRpZmZpY3VsdCB0byBkZWFsIHdpdGggbWF0aGVtYXRpY2FsbHkKMikgQmVjYXVzZSByaWNobmVzcyB2YXJpZXMgYW1vbmcgY29tbXVuaXRpZXMsIGl0IGNhbiBiZSBkaWZmaWN1bHQgdG8gY29tcGFyZSBSQURzIGFjcm9zcyBhc3NlbWJsYWdlcy4gSXQncyBub3Qgc3VjaCBhIGh1Z2UgZGVhbCB3aXRoIHRoZSBTYW13ZWxsIENhdmUgZGF0YSwgYnV0IHdvdWxkIGJlIGEgYmlnZ2VyIGlzc3VlIHdpdGggbW9yZSBkaXNwYXJpdHkgaW4gcmljaG5lc3MuCgpIZSBzdWdnZXN0cyBpbnN0ZWFkIHVzaW5nIEVDREZzIChlbXBpcmljYWwgY3VtdWxhdGl2ZSBkZW5zaXR5IGZ1bmN0aW9ucykgaW5zdGVhZC4KYGBge3J9CnBhcihtZnJvdz1jKDQsNCksIG1hcj1jKDMsMywyLDApKzAuMSkKZm9yIChpIGluIDE6bnJvdyhzY3BkU00pKXsKICBwbG90KGVjZGYoc2NwZFNNW2ksXSksIHhsYWI9IiIsIHlsYWI9IiIsIHhsaW09YygxLCAxMyksIG1haW49IiIsIHZlcnRpY2Fscz1ULCBkby5wb2ludHM9RiwgY2V4LmF4aXM9MC43NSkKICBtdGV4dChzaWRlPTIsIGxpbmU9MiwgIiUgb2YgU3BlY2llcyIsIGNleD0wLjUpCiAgbXRleHQoc2lkZT0zLCBsaW5lPTAuNSwgcGFzdGUwKCJUaW1lPSIsIGFnZXNbaV0pLCBjZXg9MC43NSkKICAgbXRleHQoc2lkZT0xLCBsaW5lPTIsICIlIGFidW5kYW5jZSIsIGNleD0wLjUpCn0KYGBgCgoqKkZvcm1hbCBtb2RlbCBmaXR0aW5nKioKCkl0J3MgcG9zc2libGUgdXNpbmcgdGhlICpzYWRzKiBwYWNrYWdlIChhbmQgYWxzbyAqdmVnYW4qLCB0aG91Z2ggdGhlIGFwcHJvYWNoZXMgZGlmZmVyKSB0byBmaXQgdmFyaW91cyBtb2RlbHMgdG8gdGhlIFNBRHMvUkFEcy4gVGhlcmUgYXJlIHF1aXRlIGEgZmV3IGRpZmZlcmVudCBtb2RlbHMgdG8gY2hvb3NlIGZyb20sIGFuZCBkaWZmZXJlbnQgYXV0aG9ycyBoYXZlIHBvc3R1bGF0ZWQgdGhhdCBkaWZmZXJlbnQgZGlzdHJpYnV0aW9ucyBhcmUgaW5kaWNhdGl2ZSBvZiBkaWZmZXJlbnQgdHlwZXMgb2YgY29tbXVuaXRpZXMuIEkndmUgcmFuZG9tbHkgY2hvc2VuIHRocmVlOiBnZW9tZXRyaWMgKGxvdyBkaXZlcnNpdHkpLCBGaXNoZXIncyBsb2ctc2VyaWVzIChtZWRpdW0gZGl2ZXJzaXR5KSwgYW5kIGxvZ25vcm1hbCAoaGlnaCBkaXZlcnNpdHkpLgpgYGB7cn0KIyBmaXQgdGhlIG1vZGVscwpzY3BkMS5nZW9tIDwtIGZpdHNhZChzY3BkU01bMSxzY3BkU01bMSxdPjBdLCAnZ2VvbScpCnNjcGQxLmxzIDwtIGZpdHNhZChzY3BkU01bMSxzY3BkU01bMSxdPjBdLCAnbHMnKQpzY3BkMS5sbm9ybSA8LSBmaXRzYWQoc2NwZFNNWzEsc2NwZFNNWzEsXT4wXSwgJ2xub3JtJykKCiMgY29tcGFyZSB0aGUgZml0IG9mIGVhY2ggbW9kZWwKQUlDdGFiKHNjcGQxLmdlb20sIHNjcGQxLmxzLCBzY3BkMS5sbm9ybSwgYmFzZT1UUlVFKQoKIyB0cmFuc2Zvcm0gdG8gYXBwcm9wcmlhdGUgY2xhc3MgZm9yIHBsb3R0aW5nCnNjcGQxLmdlb20ub2MgPC0gb2N0YXZwcmVkKHNjcGQxLmdlb20pCnNjcGQxLmxzLm9jIDwtIG9jdGF2cHJlZChzY3BkMS5scykKc2NwZDEubG5vcm0ub2MgPC0gb2N0YXZwcmVkKHNjcGQxLmxub3JtKQoKIyBwbG90IHRoZSB0aHJlZSBtb2RlbHMgYWdhaW5zdCBvbmUgYW5vdGhlciBhbmQgdGhlIGRhdGEKcGxvdChzY3BkMS5vYykKbGluZXMoc2NwZDEuZ2VvbS5vYywgY29sPSJyZWQiKQpsaW5lcyhzY3BkMS5scy5vYywgY29sPSJibHVlIikKbGluZXMoc2NwZDEubG5vcm0ub2MsIGNvbD0iZ3JlZW4iKQpsZWdlbmQoInRvcHJpZ2h0IiwgYygiZ2VvbWV0cmljIiwgIkxvZ3NlcmllcyIsICJMb2dub3JtYWwiKSwgbHR5PTEsIGNvbD1jKCJyZWQiLCJibHVlIiwgImdyZWVuIikpCmBgYAo=